#include "database_transaction.h"

#include <mysqld_error.h>

#include "database_mysql_connection.h"
#include "database_preparedstatement.h"

namespace afcore {
namespace database {

std::mutex CTransactionTask::deadlock_mutex_;

void CTransactionBase::Append(const char* sql) {
  SSqlElementData data;
  data.type = kSqlElementDataType_Raw;
  data.element.query = strdup(sql);
  queries_.emplace_back(data);
}

void CTransactionBase::AppendPreparedStatment(CPreparedStatementBase *stmt) {
  SSqlElementData data;
  data.type = kSqlElementDataType_Prepared;
  data.element.stmt = stmt;
  queries_.emplace_back(data);
}
void CTransactionBase::CleanUp() {
  if (cleaned_up_) {
    return;
  }

  for (const auto& data: queries_) {
    switch(data.type) {
      case kSqlElementDataType_Prepared:
        delete data.element.stmt;
        break;
      case kSqlElementDataType_Raw:
        free((void*)(data.element.query));
        break;
    }
  }

  queries_.clear();
  cleaned_up_ = true;
}

bool CTransactionTask::Execute() {
  int error_code = conn_->ExecuteTransaction(trans_);
  if (!error_code) {
    return true;
  }

  if (ER_LOCK_DEADLOCK == error_code) {
    std::lock_guard<std::mutex> lock(deadlock_mutex_);
    uint8_t loopbreaker = 5;
    for (uint8_t i = 0; i < loopbreaker; ++i) {
      if (!conn_->ExecuteTransaction(trans_)) {
        return true;
      }
    }
  }

  trans_->CleanUp();

  return false;
}

} // !namespace database
} // !namespace afcore